//! # 安全验证工具
//!
//! 提供各种安全相关的验证功能。

use crate::core::{SecurityError, SecurityResult, Principal, AuthContext, Resource};
use regex::Regex;
use std::collections::HashMap;
use std::time::{Duration, SystemTime};

/// 密码强度级别
#[derive(Debug, Clone, PartialEq)]
pub enum PasswordStrength {
    /// 非常弱
    VeryWeak,
    /// 弱
    Weak,
    /// 中等
    Medium,
    /// 强
    Strong,
    /// 非常强
    VeryStrong,
}

/// 验证结果
#[derive(Debug, Clone)]
pub struct ValidationResult {
    /// 是否通过验证
    pub is_valid: bool,
    /// 验证分数（0-100）
    pub score: u32,
    /// 错误消息
    pub errors: Vec<String>,
    /// 警告消息
    pub warnings: Vec<String>,
    /// 建议
    pub suggestions: Vec<String>,
}

/// 安全验证工具类
pub struct SecurityValidator {
    password_min_length: usize,
    password_max_length: usize,
    password_require_uppercase: bool,
    password_require_lowercase: bool,
    password_require_digits: bool,
    password_require_special_chars: bool,
    common_passwords: Vec<String>,
}

impl SecurityValidator {
    /// 创建新的安全验证工具实例
    pub fn new() -> Self {
        Self {
            password_min_length: 8,
            password_max_length: 128,
            password_require_uppercase: true,
            password_require_lowercase: true,
            password_require_digits: true,
            password_require_special_chars: true,
            common_passwords: Self::load_common_passwords(),
        }
    }

    /// 使用自定义配置创建验证工具
    pub fn with_config(
        min_length: usize,
        max_length: usize,
        require_uppercase: bool,
        require_lowercase: bool,
        require_digits: bool,
        require_special_chars: bool,
    ) -> Self {
        Self {
            password_min_length: min_length,
            password_max_length: max_length,
            password_require_uppercase: require_uppercase,
            password_require_lowercase: require_lowercase,
            password_require_digits: require_digits,
            password_require_special_chars: require_special_chars,
            common_passwords: Self::load_common_passwords(),
        }
    }

    /// 验证密码强度
    pub fn validate_password(&self, password: &str) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 0,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // 长度检查
        if password.len() < self.password_min_length {
            result.is_valid = false;
            result.errors.push(format!("密码长度至少需要{}个字符", self.password_min_length));
        } else {
            result.score += 20;
        }

        if password.len() > self.password_max_length {
            result.is_valid = false;
            result.errors.push(format!("密码长度不能超过{}个字符", self.password_max_length));
        }

        // 字符类型检查
        let has_uppercase = password.chars().any(|c| c.is_ascii_uppercase());
        let has_lowercase = password.chars().any(|c| c.is_ascii_lowercase());
        let has_digit = password.chars().any(|c| c.is_ascii_digit());
        let has_special = password.chars().any(|c| "!@#$%^&*()_+-=[]{}|;:,.<>?".contains(c));

        if self.password_require_uppercase && !has_uppercase {
            result.is_valid = false;
            result.errors.push("密码必须包含大写字母".to_string());
        } else if has_uppercase {
            result.score += 15;
        }

        if self.password_require_lowercase && !has_lowercase {
            result.is_valid = false;
            result.errors.push("密码必须包含小写字母".to_string());
        } else if has_lowercase {
            result.score += 15;
        }

        if self.password_require_digits && !has_digit {
            result.is_valid = false;
            result.errors.push("密码必须包含数字".to_string());
        } else if has_digit {
            result.score += 15;
        }

        if self.password_require_special_chars && !has_special {
            result.is_valid = false;
            result.errors.push("密码必须包含特殊字符".to_string());
        } else if has_special {
            result.score += 15;
        }

        // 常见密码检查
        if self.common_passwords.contains(&password.to_lowercase()) {
            result.is_valid = false;
            result.errors.push("不能使用常见密码".to_string());
        } else {
            result.score += 10;
        }

        // 重复字符检查
        if self.has_repeated_characters(password, 3) {
            result.warnings.push("密码包含重复字符".to_string());
            result.score = result.score.saturating_sub(5);
        }

        // 连续字符检查
        if self.has_sequential_characters(password) {
            result.warnings.push("密码包含连续字符".to_string());
            result.score = result.score.saturating_sub(5);
        }

        // 长度奖励
        if password.len() >= 12 {
            result.score += 10;
        }

        // 字符集多样性奖励
        let unique_chars = password.chars().collect::<std::collections::HashSet<_>>().len();
        if unique_chars as f64 / password.len() as f64 > 0.7 {
            result.score += 10;
        }

        // 提供建议
        if result.score < 50 {
            result.suggestions.push("考虑使用更长的密码".to_string());
            result.suggestions.push("增加字符类型的多样性".to_string());
        }

        result.score = result.score.min(100);
        result
    }

    /// 获取密码强度级别
    pub fn get_password_strength(&self, password: &str) -> PasswordStrength {
        let result = self.validate_password(password);
        match result.score {
            0..=20 => PasswordStrength::VeryWeak,
            21..=40 => PasswordStrength::Weak,
            41..=60 => PasswordStrength::Medium,
            61..=80 => PasswordStrength::Strong,
            81..=100 => PasswordStrength::VeryStrong,
            _ => PasswordStrength::VeryStrong, // 处理超出100的情况
        }
    }

    /// 验证邮箱地址
    pub fn validate_email(&self, email: &str) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // 基本格式检查
        let email_regex = Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap();
        if !email_regex.is_match(email) {
            result.is_valid = false;
            result.score = 0;
            result.errors.push("邮箱格式无效".to_string());
            return result;
        }

        // 长度检查
        if email.len() > 254 {
            result.is_valid = false;
            result.errors.push("邮箱地址过长".to_string());
        }

        // 域名检查
        let parts: Vec<&str> = email.split('@').collect();
        if parts.len() == 2 {
            let domain = parts[1];
            if domain.starts_with('.') || domain.ends_with('.') || domain.contains("..") {
                result.is_valid = false;
                result.errors.push("邮箱域名格式无效".to_string());
            }
        }

        // 临时邮箱检查
        if self.is_disposable_email(email) {
            result.warnings.push("使用了临时邮箱服务".to_string());
            result.score -= 20;
        }

        result
    }

    /// 验证用户名
    pub fn validate_username(&self, username: &str) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // 长度检查
        if username.len() < 3 {
            result.is_valid = false;
            result.errors.push("用户名至少需要3个字符".to_string());
        }

        if username.len() > 30 {
            result.is_valid = false;
            result.errors.push("用户名不能超过30个字符".to_string());
        }

        // 字符检查
        let username_regex = Regex::new(r"^[a-zA-Z0-9_-]+$").unwrap();
        if !username_regex.is_match(username) {
            result.is_valid = false;
            result.errors.push("用户名只能包含字母、数字、下划线和连字符".to_string());
        }

        // 开头结尾检查
        if username.starts_with('_') || username.starts_with('-') ||
           username.ends_with('_') || username.ends_with('-') {
            result.is_valid = false;
            result.errors.push("用户名不能以下划线或连字符开头/结尾".to_string());
        }

        // 保留词检查
        let reserved_words = vec!["admin", "root", "system", "api", "www", "mail", "support"];
        if reserved_words.contains(&username.to_lowercase().as_str()) {
            result.is_valid = false;
            result.errors.push("用户名是保留词".to_string());
        }

        result
    }

    /// 验证IP地址
    pub fn validate_ip_address(&self, ip: &str) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // IPv4检查
        if let Ok(_) = ip.parse::<std::net::Ipv4Addr>() {
            // 检查是否为私有IP
            if self.is_private_ip(ip) {
                result.warnings.push("使用了私有IP地址".to_string());
            }
            return result;
        }

        // IPv6检查
        if let Ok(_) = ip.parse::<std::net::Ipv6Addr>() {
            return result;
        }

        result.is_valid = false;
        result.score = 0;
        result.errors.push("IP地址格式无效".to_string());

        result
    }

    /// 验证URL
    pub fn validate_url(&self, url: &str) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // 基本URL格式检查
        match url::Url::parse(url) {
            Ok(parsed_url) => {
                // 协议检查
                match parsed_url.scheme() {
                    "http" => {
                        result.warnings.push("使用了不安全的HTTP协议".to_string());
                        result.score -= 20;
                    }
                    "https" => {
                        // HTTPS是推荐的
                    }
                    _ => {
                        result.warnings.push("使用了非标准协议".to_string());
                        result.score -= 10;
                    }
                }

                // 域名检查
                if let Some(host) = parsed_url.host_str() {
                    if host == "localhost" || host.starts_with("127.") {
                        result.warnings.push("使用了本地地址".to_string());
                    }
                }
            }
            Err(_) => {
                result.is_valid = false;
                result.score = 0;
                result.errors.push("URL格式无效".to_string());
            }
        }

        result
    }

    /// 验证认证上下文
    pub fn validate_auth_context(&self, context: &AuthContext) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // 检查是否有认证信息
        let has_bearer = context.get_bearer_token().is_some();
        let has_api_key = context.get_api_key().is_some();
        let has_basic = context.get_basic_auth().is_some();

        if !has_bearer && !has_api_key && !has_basic {
            result.warnings.push("缺少认证信息".to_string());
            result.score -= 30;
        }

        // 检查安全连接
        if !context.is_secure() {
            result.warnings.push("使用了不安全的连接".to_string());
            result.score -= 20;
        }

        // 检查客户端IP
        if let Some(ip) = context.get_client_ip() {
            let ip_result = self.validate_ip_address(ip);
            if !ip_result.is_valid {
                result.warnings.push("客户端IP地址无效".to_string());
                result.score -= 10;
            }
        } else {
            result.warnings.push("缺少客户端IP地址".to_string());
            result.score -= 10;
        }

        result
    }

    /// 验证主体信息
    pub fn validate_principal(&self, principal: &Principal) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // 检查是否过期
        if principal.is_expired() {
            result.is_valid = false;
            result.errors.push("用户认证已过期".to_string());
        }

        // 检查用户ID
        if principal.id.is_empty() {
            result.is_valid = false;
            result.errors.push("用户ID不能为空".to_string());
        }

        // 检查用户名
        if principal.name.is_empty() {
            result.warnings.push("用户名为空".to_string());
            result.score -= 10;
        }

        // 检查权限
        if principal.permissions.is_empty() && principal.roles.is_empty() {
            result.warnings.push("用户没有任何权限或角色".to_string());
            result.score -= 20;
        }

        result
    }

    /// 验证资源访问权限
    pub fn validate_resource_access(
        &self,
        principal: &Principal,
        resource: &Resource,
    ) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // 检查敏感资源
        if resource.is_sensitive() {
            if !principal.is_admin() {
                result.warnings.push("尝试访问敏感资源".to_string());
                result.score -= 30;
            }
        }

        // 检查公共资源
        if resource.is_public() {
            // 公共资源通常不需要特殊检查
            return result;
        }

        // 检查基本权限
        let required_permission = resource.get_simple_permission();
        if !principal.has_permission(&required_permission) {
            result.warnings.push(format!("缺少权限: {}", required_permission));
            result.score -= 40;
        }

        result
    }

    /// 检测SQL注入
    pub fn detect_sql_injection(&self, input: &str) -> bool {
        let sql_patterns = vec![
            r"(?i)(\bunion\b.*\bselect\b)",
            r"(?i)(\bselect\b.*\bfrom\b)",
            r"(?i)(\binsert\b.*\binto\b)",
            r"(?i)(\bupdate\b.*\bset\b)",
            r"(?i)(\bdelete\b.*\bfrom\b)",
            r"(?i)(\bdrop\b.*\btable\b)",
            r"(?i)(\balter\b.*\btable\b)",
            r"(?i)(--|#|/\*|\*/)",
            r"(?i)(\bor\b.*=.*\bor\b)",
            r"(?i)(\band\b.*=.*\band\b)",
            r"'.*'",
            r#"".*""#,
        ];

        for pattern in sql_patterns {
            if let Ok(regex) = Regex::new(pattern) {
                if regex.is_match(input) {
                    return true;
                }
            }
        }

        false
    }

    /// 检测XSS攻击
    pub fn detect_xss(&self, input: &str) -> bool {
        let xss_patterns = vec![
            r"(?i)<script[^>]*>.*?</script>",
            r"(?i)<iframe[^>]*>.*?</iframe>",
            r"(?i)<object[^>]*>.*?</object>",
            r"(?i)<embed[^>]*>",
            r"(?i)<link[^>]*>",
            r"(?i)javascript:",
            r"(?i)vbscript:",
            r"(?i)onload\s*=",
            r"(?i)onerror\s*=",
            r"(?i)onclick\s*=",
            r"(?i)onmouseover\s*=",
        ];

        for pattern in xss_patterns {
            if let Ok(regex) = Regex::new(pattern) {
                if regex.is_match(input) {
                    return true;
                }
            }
        }

        false
    }

    /// 检测路径遍历攻击
    pub fn detect_path_traversal(&self, input: &str) -> bool {
        let patterns = vec![
            r"\.\./",
            r"\.\.\\",
            r"%2e%2e%2f",
            r"%2e%2e%5c",
            r"..%2f",
            r"..%5c",
        ];

        for pattern in patterns {
            if let Ok(regex) = Regex::new(pattern) {
                if regex.is_match(input) {
                    return true;
                }
            }
        }

        false
    }

    /// 验证输入安全性
    pub fn validate_input_security(&self, input: &str) -> ValidationResult {
        let mut result = ValidationResult {
            is_valid: true,
            score: 100,
            errors: Vec::new(),
            warnings: Vec::new(),
            suggestions: Vec::new(),
        };

        // SQL注入检测
        if self.detect_sql_injection(input) {
            result.is_valid = false;
            result.errors.push("检测到SQL注入攻击".to_string());
        }

        // XSS检测
        if self.detect_xss(input) {
            result.is_valid = false;
            result.errors.push("检测到XSS攻击".to_string());
        }

        // 路径遍历检测
        if self.detect_path_traversal(input) {
            result.is_valid = false;
            result.errors.push("检测到路径遍历攻击".to_string());
        }

        // 长度检查
        if input.len() > 10000 {
            result.warnings.push("输入内容过长".to_string());
            result.score -= 20;
        }

        // 特殊字符检查
        let suspicious_chars = ['<', '>', '"', '\'', '&', ';', '(', ')', '{', '}'];
        let suspicious_count = input.chars()
            .filter(|c| suspicious_chars.contains(c))
            .count();

        if suspicious_count > input.len() / 10 {
            result.warnings.push("包含大量特殊字符".to_string());
            result.score -= 10;
        }

        result
    }

    // 辅助方法
    fn has_repeated_characters(&self, password: &str, threshold: usize) -> bool {
        let mut char_counts = HashMap::new();
        for c in password.chars() {
            *char_counts.entry(c).or_insert(0) += 1;
        }

        char_counts.values().any(|&count| count >= threshold)
    }

    fn has_sequential_characters(&self, password: &str) -> bool {
        let chars: Vec<char> = password.chars().collect();
        for window in chars.windows(3) {
            let a = window[0] as u8;
            let b = window[1] as u8;
            let c = window[2] as u8;

            if (b == a + 1 && c == b + 1) || (b == a - 1 && c == b - 1) {
                return true;
            }
        }
        false
    }

    fn load_common_passwords() -> Vec<String> {
        vec![
            "password".to_string(),
            "123456".to_string(),
            "123456789".to_string(),
            "qwerty".to_string(),
            "abc123".to_string(),
            "password123".to_string(),
            "admin".to_string(),
            "letmein".to_string(),
            "welcome".to_string(),
            "monkey".to_string(),
        ]
    }

    fn is_disposable_email(&self, email: &str) -> bool {
        let disposable_domains = vec![
            "10minutemail.com",
            "tempmail.org",
            "guerrillamail.com",
            "mailinator.com",
            "yopmail.com",
        ];

        if let Some(domain) = email.split('@').nth(1) {
            disposable_domains.contains(&domain.to_lowercase().as_str())
        } else {
            false
        }
    }

    fn is_private_ip(&self, ip: &str) -> bool {
        if let Ok(addr) = ip.parse::<std::net::Ipv4Addr>() {
            addr.is_private() || addr.is_loopback() || addr.is_link_local()
        } else {
            false
        }
    }
}

impl Default for SecurityValidator {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::PrincipalType;

    #[test]
    fn test_password_validation() {
        let validator = SecurityValidator::new();

        // 强密码
        let strong_result = validator.validate_password("MyStr0ng!P@ssw0rd");
        assert!(strong_result.is_valid);
        assert!(strong_result.score >= 80);

        // 弱密码
        let weak_result = validator.validate_password("123");
        assert!(!weak_result.is_valid);
        assert!(weak_result.score < 50);

        // 常见密码
        let common_result = validator.validate_password("password");
        assert!(!common_result.is_valid);
    }

    #[test]
    fn test_password_strength() {
        let validator = SecurityValidator::new();

        assert_eq!(
            validator.get_password_strength("MyStr0ng!P@ssw0rd"),
            PasswordStrength::VeryStrong
        );

        assert_eq!(
            validator.get_password_strength("123"),
            PasswordStrength::VeryWeak
        );
    }

    #[test]
    fn test_email_validation() {
        let validator = SecurityValidator::new();

        let valid_result = validator.validate_email("user@example.com");
        assert!(valid_result.is_valid);

        let invalid_result = validator.validate_email("invalid-email");
        assert!(!invalid_result.is_valid);

        let disposable_result = validator.validate_email("user@10minutemail.com");
        assert!(disposable_result.is_valid);
        assert!(!disposable_result.warnings.is_empty());
    }

    #[test]
    fn test_username_validation() {
        let validator = SecurityValidator::new();

        let valid_result = validator.validate_username("valid_user123");
        assert!(valid_result.is_valid);

        let invalid_result = validator.validate_username("ab");
        assert!(!invalid_result.is_valid);

        let reserved_result = validator.validate_username("admin");
        assert!(!reserved_result.is_valid);
    }

    #[test]
    fn test_security_detection() {
        let validator = SecurityValidator::new();

        // SQL注入检测
        assert!(validator.detect_sql_injection("'; DROP TABLE users; --"));
        assert!(!validator.detect_sql_injection("normal input"));

        // XSS检测
        assert!(validator.detect_xss("<script>alert('xss')</script>"));
        assert!(!validator.detect_xss("normal input"));

        // 路径遍历检测
        assert!(validator.detect_path_traversal("../../../etc/passwd"));
        assert!(!validator.detect_path_traversal("normal/path"));
    }

    #[test]
    fn test_input_security_validation() {
        let validator = SecurityValidator::new();

        let safe_result = validator.validate_input_security("safe input");
        assert!(safe_result.is_valid);

        let malicious_result = validator.validate_input_security("'; DROP TABLE users; --");
        assert!(!malicious_result.is_valid);
    }

    #[test]
    fn test_principal_validation() {
        let validator = SecurityValidator::new();

        let valid_principal = Principal::new(
            "user123".to_string(),
            "John Doe".to_string(),
            PrincipalType::User,
        ).add_role("user".to_string());

        let result = validator.validate_principal(&valid_principal);
        assert!(result.is_valid);

        let empty_principal = Principal::new(
            "".to_string(),
            "".to_string(),
            PrincipalType::User,
        );

        let empty_result = validator.validate_principal(&empty_principal);
        assert!(!empty_result.is_valid);
    }
}